package com.yootoo.extpmml.service.impl;

import com.alibaba.fastjson.JSON;
import com.yootoo.extpmml.Entites.model.ModelDesc;
import com.yootoo.extpmml.Entites.ModelEvaluator;
import com.yootoo.extpmml.Exception.ModelException;
import com.yootoo.extpmml.Exception.ModelExecuteException;
import com.yootoo.extpmml.controller.ModelExcuteController;
import com.yootoo.extpmml.mapper.BaseMapper;
import com.yootoo.extpmml.service.BaseOperateService;
import com.yootoo.extpmml.utils.ModelHelper;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ModelOperateServiceImpl implements BaseOperateService<ModelDesc>{
    private static final Logger LOGGER = LoggerFactory.getLogger(ModelExcuteController.class);

    @Autowired
    private BaseMapper<ModelDesc> modelMapper;
    //活跃模型evaluators
    private Map<String,ModelEvaluator> evaluators = Maps.newConcurrentMap();

    @PostConstruct
    public void init() {
        List<ModelDesc> allModels = modelMapper.findAll();
        for (ModelDesc modelDesc : allModels){
            try {
                ModelHelper.addToEvaluators(evaluators,modelDesc);
            } catch (Exception e) {
                LOGGER.error("加载模型失败 {},model: {}",e.getMessage(),modelDesc);
            }
        }
        LOGGER.info("加载模型成功,Size: {}",allModels.size());
    }

    @Override
    public Map<String, Object> execute(String name, String record) {
        Map<String,Object> inputVars = JSON.parseObject(record, HashMap.class);
        if (!evaluators.containsKey(name)){
            //read from db
            ModelDesc model = modelMapper.find(name);
            if (model == null || model.getState() != 1){
                throw new ModelExecuteException("模型未上线");
            }
            ModelHelper.addToEvaluators(evaluators,model);
        }
        ModelEvaluator evaluator = evaluators.get(name);
        return executeModel(evaluator, evaluator.getModel().getFeatures(), inputVars);
    }

    @Override
    public Map<String, Object> test(String name, String record) {
        Map<String,Object> inputVars = JSON.parseObject(record, HashMap.class);
        //read from db
        ModelDesc model = modelMapper.find(name);
        if (model == null){
            throw new ModelException("模型未上传");
        }
        if (model.getState() == 1){
            throw new ModelException("只能测试状态为0或-1的模型");
        }
        return executeModel(ModelHelper.toEvaluator(model),model.getFeatures(),inputVars);
    }

    private Map<String, Object> executeModel(ModelEvaluator evaluator,String features, Map<String, Object> inputVars) {
        if (features == null || features.trim().length() == 0){
            throw new ModelExecuteException("模型输入校验失败,输入系列特征名feature_names不能为空");
        }

        String[] featureNameArr = features.split(",", -1);
        for (String featureName : featureNameArr){
            if (!inputVars.containsKey(featureName)){
                LOGGER.warn("特征名[" + featureName + "]不存在输入变量中,给默认值-9999999");
                inputVars.put(featureName,-9999999);
            }
        }

        Map<String, Object> res;
        try {
            res = evaluator.execute(inputVars,featureNameArr);
        } catch (Exception e) {
            LOGGER.error("模型执行异常",e);
            throw new ModelExecuteException("模型执行异常:"+e.getMessage(),e);
        }
        return res;
    }


    @Override
    public ModelDesc up(String name) {
        ModelDesc model = modelMapper.find(name);
        if (model == null){
            throw new ModelException("模型不存在");
        }
        if (model.getState() == 1){
            throw new ModelException("模型已经在线");
        }
        model.setState(1);
        modelMapper.update(model);
        ModelHelper.addToEvaluators(evaluators,model);
        return model;
    }

    @Override
    public ModelDesc down(String name) {
        ModelDesc model = modelMapper.find(name);
        if (model == null){
            throw new ModelException("模型不存在");
        }
        if (model.getState() == -1){
            throw new ModelException("模型已经下线");
        }
        model.setState(-1);
        modelMapper.update(model);
        evaluators.remove(name);
        return model;
    }

    @Override
    public ModelDesc upload(ModelDesc model) {
        if (model == null){
            throw new ModelException("模型不能为空");
        }
        ModelDesc _model = modelMapper.find(model.getName());
        if (_model != null){
            throw new ModelException("模型已经存在");
        }
        if (model.getState() != 0){
            throw new ModelException("模型状态异常state=" + model.getState());
        }
        modelMapper.insert(model);
        return model;
    }

    @Override
    public ModelDesc update(ModelDesc model,boolean force) {
        if (model == null){
            throw new ModelException("模型不能为空");
        }
        ModelDesc _model = modelMapper.find(model.getName());
        if (_model == null){
            throw new ModelException("模型不存在,不能被更新.");
        }
        if (!force){
            if ( _model.getState() == 1){
                throw new ModelException("模型已经存在,并且上线状态,不能被更新,请先下线.");
            }
            if (model.getState() != 0){
                throw new ModelException("模型状态异常state=" + model.getState());
            }
            if (_model.getState() != 1){
                modelMapper.update(model);
            }
        }else{
            model.setState(_model.getState());
            ModelHelper.addToEvaluators(evaluators,model);
            modelMapper.update(model);
        }
        return model;
    }
}
